#include <iostream>
#include <string>
#include <memory>
#include <ctime>
#include "Socket.hpp"
#include "Protocol.hpp"
#include "InetAddr.hpp"

using namespace socket_ns;
using namespace protocol_ns;

void Usage(std::string proc)
{
  std::cout << "Usage:\n\t" << proc << " serverip serverport\n"
            << std::endl;
}

// ./tcp_client serverip serverport
int main(int argc, char *argv[])
{
  if (argc != 3)
  {
    Usage(argv[0]);
    exit(1);
  }
  std::string serverip = argv[1];
  uint16_t serverport = std::stoi(argv[2]);
  InetAddr serveraddr(serverip, serverport);
  Factory factory;
  std::unique_ptr<Socket> cli = std::make_unique<TcpSocket>();
  bool res = cli->BuildClientSocket(serveraddr);
  std::string inbuffer;
  while (res)
  {
    sleep(1);
    // std::string str;
    // // 一次构建五个请求，测试服务器对积压请求处理
    // for (int i = 0; i < 5; i++)
    // {
    //   // 1.构建一个请求
    //   auto req = factory.BuildRequest();

    //   // 2. 对请求进行序列化
    //   std::string send_str;
    //   req->Serialize(&send_str);

    //   std::cout << "请求序列化: \n"
    //             << send_str << std::endl;

    //   // 3. 添加长度报头
    //   send_str = Encode(send_str);
    //   std::cout << "请求完整报文: \n"
    //             << send_str << std::endl;
    //   str += send_str;
    // }

    // 1.构建一个请求
    auto req = factory.BuildRequest();

    // 2. 对请求进行序列化
    std::string send_str;
    req->Serialize(&send_str);

    std::cout << "请求序列化: \n"
              << send_str << std::endl;

    // 3. 添加长度报头
    send_str = Encode(send_str);
    std::cout << "请求完整报文: \n"
              << send_str << std::endl;
    // 4. "len"\r\n"{}"\r\n
    cli->Send(send_str);

    // 5. 读取服务器响应
    int n = cli->Recv(&inbuffer);
    if (n <= 0)
      break;
    std::string package = Decode(inbuffer);
    if (package.empty())
      continue;
    // 6. 我能保证package一定是一个完整的响应！
    auto resp = factory.BuildResponse();
    // 6.1 反序列化
    resp->Deserialize(package);

    // 7. 拿到了结构化的响应
    std::cout << "计算结果: " << resp->_result << "[" << resp->_code << "]" << std::endl;
  }
  return 0;
}